/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "parameter.h"
#include "flash_if.h"

#if 1
    #include <stdio.h>
    #define PRINTF printf
#else
    #define PRINTF(...)
#endif
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint16_t CRC16_Modbus(uint8_t *pBuf, uint32_t dataLen);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
    /* USER CODE BEGIN 1 */
    int ret = 0;
    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    /* USER CODE BEGIN 2 */
    PRINTF("\n\rEtherCAT common bootloader\n\r");
    PRINTF("Build %s %s\n\r", __DATE__, __TIME__);
    PRINTF("Parameter Init.\n\r");
    ret = ParameterInit();
    if(ret != 0)
    {
        PRINTF("Parameter Init KO. %d\n\r", ret);
        Error_Handler();
    }

    if (btdata.appinfo->swver == 0xFFFFFFFF && btdata.downinfo->swver == 0xFFFFFFFF)
    {
        PRINTF("There is no firmware both in application zone or download zone .\n\r");
        PRINTF("Please download the application firmware or contact with your supplier.\n\r");
        Error_Handler();
    }
    else if (btdata.downinfo->swver > btdata.appinfo->swver && btdata.downinfo->swver != 0xFFFFFFFF)
    {
        uint16_t ccrc;
        PRINTF("App Version %d.%d.%d , Down Version %d.%d.%d\n\r", btdata.appinfo->ver_major, btdata.appinfo->ver_minor,btdata.appinfo->ver_revision,
        btdata.downinfo->ver_major, btdata.downinfo->ver_minor,btdata.downinfo->ver_revision);
        PRINTF("DownloadAddress is %08X, data byte length is %u.\n\r", btdata.DownloadAddress, btdata.downByteLen);
        ccrc = CRC16_Modbus((uint8_t *)btdata.DownloadAddress, btdata.downByteLen);
        if (ccrc != btdata.downCRC)
        {
            PRINTF("Download data block CRC is bad.ccrc %04X downCRC %04X\n\r", ccrc, btdata.downCRC);
            Error_Handler();
        }
        else
        {
            PRINTF("Download data block CRC check pass.\n\r");
            PRINTF("Erasing application zone.\n\r");
            FLASH_If_Init();
            ret = FLASH_If_Erase(ADDR_FLASH_SECTOR_5);
            if(0 != ret)
            {
                PRINTF("Erase application zone KO. %d\n\r", ret);
                Error_Handler();
            }
            PRINTF("Copying data to application zone.\n\r");
            ret = FLASH_If_Write(btdata.ApplicationAddress,(uint32_t*)btdata.DownloadAddress,(btdata.downByteLen+3)>>2);
            if(0 != ret)
            {
                PRINTF("Copy data to application zone KO. %d\n\r", ret);
                Error_Handler();
            }
            HAL_FLASH_Lock();
            goto runapp;
        }
        // PRINTF("Update App Version %d to %d\n\r", btdata.appinfo->swver, btdata.downinfo->swver);
    }
    else
    {
runapp:
        /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
        if (((*(__IO uint32_t *)btdata.ApplicationAddress) & 0x2FFE0000) == 0x20000000)
        {
            /* Jump to user application */
            btdata.JumpAddress = *(__IO uint32_t *)(btdata.ApplicationAddress + 4);
            btdata.JumpToApplication = (pFunction)btdata.JumpAddress;
            /* Initialize user application's Stack Pointer */
            __set_MSP(*(__IO uint32_t *)btdata.ApplicationAddress);
            btdata.JumpToApplication();
        }
    }
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        for (int i = 0; i < 4 * 1000000; i++)
            ;
        HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
    }
    /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
     */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
 * @brief USART1 Initialization Function
 * @param None
 * @retval None
 */
void MX_USART1_UART_Init(void)
{

    /* USER CODE BEGIN USART1_Init 0 */

    /* USER CODE END USART1_Init 0 */

    LL_USART_InitTypeDef USART_InitStruct = {0};

    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* Peripheral clock enable */
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);

    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
    /**USART1 GPIO Configuration
    PA9   ------> USART1_TX
    PA10   ------> USART1_RX
    */
    GPIO_InitStruct.Pin = LL_GPIO_PIN_9 | LL_GPIO_PIN_10;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USER CODE BEGIN USART1_Init 1 */

    /* USER CODE END USART1_Init 1 */
    USART_InitStruct.BaudRate = 115200;
    USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
    USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
    USART_InitStruct.Parity = LL_USART_PARITY_NONE;
    USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
    USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
    LL_USART_Init(USART1, &USART_InitStruct);
    LL_USART_ConfigAsyncMode(USART1);
    LL_USART_Enable(USART1);
    /* USER CODE BEGIN USART1_Init 2 */

    /* USER CODE END USART1_Init 2 */
}

/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOG_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_RESET);

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5 | GPIO_PIN_8, GPIO_PIN_RESET);

    /*Configure GPIO pin : PG7 */
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

    /*Configure GPIO pins : PB5 PB8 */
    GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/* USER CODE BEGIN 4 */
int fputc(int ch, FILE *f)
{
#ifndef USE_FULL_LL_DRIVER
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
#else
    while (!LL_USART_IsActiveFlag_TXE(USART1))
    {
    }
    LL_USART_TransmitData8(USART1, (uint8_t)ch);
    while (!LL_USART_IsActiveFlag_TC(USART1))
    {
    }
#endif
    return ch;
}
int fgetc(FILE *f)
{
#ifndef USE_FULL_LL_DRIVER
    int ch = 0;
    HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
#else
    while (!LL_USART_IsActiveFlag_RXNE(USART1))
    {
    }
    return LL_USART_ReceiveData8(USART1);
#endif
}
uint16_t CRC16_Modbus(uint8_t *pBuf, uint32_t dataLen)
{
    typedef union {
        uint16_t val;
        struct
        {
            uint16_t bit0 : 1;
            uint16_t bit1 : 1;
            uint16_t bit2 : 1;
            uint16_t bit3 : 1;
            uint16_t bit4 : 1;
            uint16_t bit5 : 1;
            uint16_t bit6 : 1;
            uint16_t bit7 : 1;
            uint16_t bit8 : 1;
            uint16_t bit9 : 1;
            uint16_t bit10 : 1;
            uint16_t bit11 : 1;
            uint16_t bit12 : 1;
            uint16_t bit13 : 1;
            uint16_t bit14 : 1;
            uint16_t bit15 : 1;
        } bits;
    } CRCReg;
    int i;
    uint8_t j, nTest;
    CRCReg reg;

    reg.val = 0xFFFF;
    for (i = 0; i < dataLen; i++)
    {
        reg.val ^= *pBuf++;
        for (j = 0; j < 8; j++)
        {
            nTest = (reg.bits.bit0) ? 0x01 : 0x00;
            reg.val >>= 1;
            if (nTest == 1)
                reg.val ^= 0xA001;
        }
    }
    reg.val = (((reg.val >> 8)) + ((reg.val) << 8));
    return reg.val;
}

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
    while (1)
    {
        for (int i = 0; i < 2 * 300000; i++)
            ;
        HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
